package com.llb666.java.collection.list;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author 斌~
 * @version 1.0
 * @date 2021/3/20 下午10:14
 */

public class ArrayListError {

    public static void initCollection(){
        List<String> list  = new ArrayList<>();
        System.out.println("add之前的数组长度"+getArrayListCapacity(list));
        list.add("hello");
        System.out.println("add之后的数组长度"+getArrayListCapacity(list));
        Object[] objects = list.toArray();
        System.out.println(objects.getClass().getSimpleName());
        //注意ArrayList的初始化长度为0，只有add之后才会是10,没有add会报错
        objects[0] =new Object();
        System.out.println(objects[0]);
    }

    /**
     * 指定初始数据初始化时，我们发现一个这样子的注释 see 6260652，这是 Java 的一个 bug，
     * 意思是当给定集合内的元素不是 Object 类型时，我们会转化成 Object 的类型。一般情况下都不会触发此 bug，
     * 只有在下列场景下才会触发：
     * ArrayList 初始化之后（ArrayList 元素非 Object 类型），
     * 再次调用 toArray 方法，得到 Object 数组，并且往 Object 数组赋值时，才会触发此 bug
     * java.lang.ArrayStoreException
     */
    public static void initCollection2(){
        // Arrays.asList 具体返回的类型
//        List<String> list  = Arrays.asList("hello,world");

        List<Integer> list  = Arrays.asList(1);
        Object[] objects = list.toArray();
        System.out.println(objects.getClass().getSimpleName());
        //objects元素类型是String，存储Object就会报错，因为jvm不知道你存储的真是类型是不是String
        //  1.9之后修复了该bug
        objects[0] =new Object();
        System.out.println(objects[0]);
    }
    public static void main(String[] args) {
        initCollection2();
    }


    /**
     * 获取 ArrayList 的数组容量
     * @param arrayList 集合
     * @return int
     */
    public static int getArrayListCapacity(List<?> arrayList) {
        Class<ArrayList> arrayListClass = ArrayList.class;
        try {
            /*
             * getField 只能获取public的，包括从父类继承来的字段。
             * getDeclaredField 可以获取本类所有的字段，包括private的，但是不能获取继承来的字段。
             * (注： 这里只能获取到private的字段，但并不能访问该private字段的值,除非加上setAccessible(true))
             */
            Field field = arrayListClass.getDeclaredField("elementData");
            field.setAccessible(true);//用反射时访问私有变量
            Object[] objects = (Object[]) field.get(arrayList);//获取arrayList的elementData值
            return objects.length;
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
            return -1;
        }
    }
}
